﻿using Python.Runtime;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace cs2py
{
    /// <summary>
    /// 
    /// </summary>
    public class UsePythonnet
    {
        private const string PyFile_calcE = "./pys/calcE.py";
        private const string PyFile_draw_axis = "./pys/draw_axis.py";

        public static void Init()
        {
            //Runtime.PythonDLL = Path.Combine(
            //    Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
            //    , @"Programs\Python\Python311\python311.dll");
            //Runtime.PythonDLL = SearchPythonPath();
            //支持嵌入式Python
            //Runtime.PythonDLL = @".\python311\python311.dll";
            //Runtime.PythonDLL = @".\python312\python312.dll";
            Runtime.PythonDLL = @".\python310\python310.dll";
            //"python -m debugpy --listen 5678"
            var args = new List<string>()
            {
                //"-X frozen_modules=off"
                //"-m debugpy",
                //"--listen 5678",
                //"--wait-for-client",
            };
            PythonEngine.DebugGIL = true;
            PythonEngine.Initialize(args);
        }

        public static void Init(string dll)
        {
            Runtime.PythonDLL = dll;
            PythonEngine.Initialize();
        }

        public static void Shutdown()
        {
            PythonEngine.Shutdown();
        }

        public static string CheckEnvironment()
        {
            var builder = new StringBuilder();
            builder.AppendFormat("DLL:{0}\n", Runtime.PythonDLL);
            builder.AppendFormat("MainManagedThreadId:{0}\n", Runtime.MainManagedThreadId);
            builder.AppendFormat("IsInitialized:{0}\n", PythonEngine.IsInitialized);
            builder.AppendFormat("Platform:{0}\n", PythonEngine.Platform);
            builder.AppendFormat("Compiler:{0}\n", PythonEngine.Compiler);
            builder.AppendFormat("BuildInfo:{0}\n", PythonEngine.BuildInfo);
            builder.AppendFormat("Version:{0}\n", PythonEngine.Version);
            builder.AppendFormat("MinSupportedVersion:{0}\n", PythonEngine.MinSupportedVersion);
            builder.AppendFormat("MaxSupportedVersion:{0}\n", PythonEngine.MaxSupportedVersion);
            builder.AppendFormat("ProgramName:{0}\n", PythonEngine.ProgramName);
            builder.AppendFormat("PythonHome:{0}\n", PythonEngine.PythonHome);
            builder.AppendFormat("PythonPath:{0}\n", PythonEngine.PythonPath);
            //builder.AppendFormat("Copyright:{0}\n", PythonEngine.Copyright);
            builder.AppendFormat("PythonThreadID:{0}\n", PythonEngine.GetPythonThreadID());
            return builder.ToString();
        }

        public static string RunScript(string script, string func)
        {
            var builder = new StringBuilder();
            using (Py.GIL())
            {
                try
                {
                    var mdl = Py.CreateScope();
                    var code = script;
                    var ret = mdl.Exec(code);
                    var f = ret.Get(func);
                    var r0 = f.Invoke();
                    builder.AppendLine(r0.ToString());
                }
                catch (Exception e)
                {
                    builder.AppendLine(e.Message);
                    builder.AppendLine(e.StackTrace);
                    builder.AppendLine(e.Source);
                    Console.WriteLine(e.Message);
                }
                finally
                {
                }
            }
            return builder.ToString();
        }

        public static string SearchPythonPath()
        {
            var p1 = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
                , @"Programs\Python\");
            var tpl = "{0}.dll";
            if (Directory.Exists(p1))
            {
                var dirs = new DirectoryInfo(p1)
                    .GetDirectories().ToList()
                    .Where(d => d.Name.StartsWith("Python"));
                foreach (var d in dirs)
                {
                    var dn = d.Name;
                    var dll = string.Format(tpl, dn.ToLower());
                    var fn = Path.Combine(p1, dn, dll);
                    if (File.Exists(fn))
                    {
                        return fn;
                    }
                }
            }
            return "";

        }

        [Obsolete]
        public static string SearchPythonDll()
        {
            var p = new Process();
            p.StartInfo = new ProcessStartInfo()
            {
                LoadUserProfile = false,
                Verb = "runas",
                CreateNoWindow = true,
                RedirectStandardOutput = true,
                RedirectStandardInput = true,
                UseShellExecute = false,
                FileName = "cmd.exe",
                WorkingDirectory = @"C:\WINDOWS\System32",
            };
            p.Start();
            p.StandardInput.WriteLine("where python");
            p.StandardInput.WriteLine("exit");
            var reader = p.StandardOutput;
            while (!p.HasExited)
            {
                Thread.Sleep(200);
            }
            //丢失一个
            var str = reader.ReadToEnd();
            var strs = str.Split('\n');
            var dlls = strs.ToList()
                .Select(d => d.TrimEnd())
                .Where(d => File.Exists(d))
                .Select(d =>
            {
                var dir = Path.GetDirectoryName(d);
                return Path.Combine(dir, dir + ".dll");
            });
            return "";
        }

        public static void Run()
        {
            Console.WriteLine();
            Console.WriteLine("Python.Net");
            Console.WriteLine("********************");
            Exec_Intergate(PysFiles.Py_intergate_numpy, 1, 10);
            Exec_Intergate(PysFiles.Py_intergate_scipy, 1, 10);
            Exec_Intergate(PysFiles.Py_intergate_sympy, 1, 10);

            ExecPyFileIntrop(PysFiles.Py_Introp);
            ExecPyFileSateOrbit(PysFiles.Py_SateOrbit);
        }

        private static void Exec_Intergate(string file, float start, float stop)
        {
            using (Py.GIL())
            {
                try
                {
                    var mdl = Py.CreateScope();
                    var code = "";
                    using (var reader = new StreamReader(File.OpenRead(file)))
                    {
                        code = reader.ReadToEnd();
                    }
                    var ret = mdl.Exec(code);
                    var name = Path.GetFileNameWithoutExtension(file);
                    var func = ret.Get(name);
                    var p1 = start.ToPython();
                    var p2 = stop.ToPython();
                    var r0 = func.Invoke(p1, p2);
                    var r1 = r0.As<float>();
                    Console.WriteLine(name + "积分结果：" + r1);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
                finally
                {
                }
            }
        }

        private static void ExecPyFileE(string file)
        {
            using (Py.GIL())
            {
                var mdl = Py.CreateScope();
                var code = "";
                using (var reader = new StreamReader(File.OpenRead(file)))
                {
                    code = reader.ReadToEnd();
                }
                var ret = mdl.Exec(code);
                var func = ret.Get(Path.GetFileNameWithoutExtension(file));
                float e = func.Invoke().As<float>();
                Console.WriteLine("Py E:" + e);
                Console.WriteLine(".Net E:" + Math.E);
            }
        }

        private static void ExecPyFileDraw(string file)
        {
            using (Py.GIL())
            {
                var mdl = Py.CreateScope();
                var code = "";
                using (var reader = new StreamReader(File.OpenRead(file)))
                {
                    code = reader.ReadToEnd();
                }
                var ret = mdl.Exec(code);
                var func = ret.Get(Path.GetFileNameWithoutExtension(file));
                var ret2 = func.Invoke();
            }
        }

        private static void ExecPyFileSateOrbit(string file)
        {
            using (Py.GIL())
            {
                var mdl = Py.CreateScope();
                var code = "";
                using (var reader = new StreamReader(File.OpenRead(file)))
                {
                    code = reader.ReadToEnd();
                }
                var ret = mdl.Exec(code);
                var func = ret.Get("OrbitPostionVelocity");
                var ret2 = func.Invoke();
                var res = ret2.As<float[]>();

                var func2 = ret.Get("OrbitPostionVelocity2");
                var ret22 = func2.Invoke(10.ToPython());
                var res2 = ret22.As<PyTuple[]>();
                var nf = new NumberFormatInfo();
                for (int i = 0; i < res2.Length; i++)
                {
                    res2[i].ToArray().ToList()
                        .Select(d => d.ToSingle(nf))
                        .ToList()
                        .ForEach(d => Console.Write(d + "\t"));
                    Console.WriteLine();
                }
            }
        }

        private static void ExecPyFileIntrop(string file)
        {
            var form = new Form()
            {
                Text = "C#代码定义的窗口"
            };
            using (var state = Py.GIL())
            {
                //Py.SetArgv("-Xfrozen_modules=off");
                var mdl = Py.CreateScope();
                var code = "";
                using (var reader = new StreamReader(File.OpenRead(file)))
                {
                    code = reader.ReadToEnd();
                }
                var ret = mdl.Exec(code);
                var func = ret.Get(Path.GetFileNameWithoutExtension(file));
                var p = form.ToPython();

                func.Invoke(p);
                //Console.WriteLine("Py E:" + e);
                Console.WriteLine(".Net E:" + Math.E);
            }
        }

        private static void StartVsCodeDebug()
        {

        }

    }
}